﻿using System;
using System.Configuration;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.XPath;

using Microsoft.Ddue.Tools;


namespace ClickDiag
{
    /// <summary>
    /// Класс компонента диаграмм
    /// </summary>
    public class DiagramComponent : BuildComponent
    {
        List<ClickDiagramm> diagramList;
        string
            manifestFile = null,
            manifestConceptFile = null,
            diagramPath = null,
            projectFolder = null;

        bool manifestExist = false;
        bool manifestConceptExist = false;

        /// <summary>
        /// Конструктор класса DiagramComponent. 
        /// Копирует диаграммы в рабочую папку. Строит карты нажатий всех диаграмм из директории.
        /// </summary>
        /// <param name="assembler">BuildAssembler</param>
        /// <param name="configuration">Доступ к файлу конфигурации</param>
        public DiagramComponent(BuildAssembler assembler, XPathNavigator configuration) :
            base(assembler, configuration)
        {
            //-------------------------------------Get Config Paths-------------------------------
          
            XPathNavigator navi;

            navi = configuration.SelectSingleNode("manifestPath");
            if (navi != null)
                manifestFile = navi.GetAttribute("value", String.Empty);

            navi = configuration.SelectSingleNode("manifestConcPath");
            if (navi != null)
                manifestConceptFile = navi.GetAttribute("value", String.Empty);

            navi = configuration.SelectSingleNode("diagramPath");
            if (navi != null)
                diagramPath = navi.GetAttribute("value", String.Empty);

            navi = configuration.SelectSingleNode("projectPath");
            if (navi != null)
                projectFolder = navi.GetAttribute("value", String.Empty);

            navi = configuration.SelectSingleNode("manifestConcPath");
            if (navi != null)
                manifestConceptFile = navi.GetAttribute("value", String.Empty);

            if (String.IsNullOrEmpty(manifestFile) || String.IsNullOrEmpty(diagramPath) || String.IsNullOrEmpty(manifestConceptFile))
                base.WriteMessage(MessageLevel.Error, "Configuration Error! Manifest or Diagram Fail");

            //-------------------------------------Copy to {@Output}/Diagrams-------------------------------

            string outFolder = null;

            navi = configuration.SelectSingleNode("outputPath");
            if (navi != null)
                outFolder = navi.GetAttribute("value", String.Empty) + "Diagrams\\";

            if (String.IsNullOrEmpty(outFolder))
                base.WriteMessage(MessageLevel.Error, "Configuration Error! Output Fail");

            DirectoryInfo di_Out = new DirectoryInfo(outFolder);
            if (!di_Out.Exists)
                di_Out.Create();

            DirectoryInfo di_In = new DirectoryInfo(diagramPath);
            foreach (FileInfo fi in di_In.GetFiles())
                fi.CopyTo(di_Out.FullName + fi.Name, true);

            //----------------------------------Build All diagrams--------------------------------------------------

            XmlDocument xManifest = new XmlDocument();
            XmlDocument xManifestConcept = new XmlDocument();

            try
            {
                xManifest.Load(manifestFile);
                manifestExist = true;
            }
            catch (Exception e)
            {
                manifestExist = false;
                base.WriteMessage(MessageLevel.Warn, "Init... Manifest.xml file error. Simply images.");
            }

            try
            {                              
                xManifestConcept.Load(manifestConceptFile);
                manifestConceptExist = true;
            }
            catch (Exception e)
            {
                manifestConceptExist = false;
                base.WriteMessage(MessageLevel.Warn, "Init... ManifestConcept.xml file error. Simply images.");
            }

            FileInfo[] finfoArr = di_Out.GetFiles("*.cd");

            diagramList = new List<ClickDiagramm>(finfoArr.Length);

            foreach (FileInfo fin in finfoArr)
            {
                diagramList.Add(new ClickDiagramm(fin.FullName, projectFolder));
                
                if (manifestExist)
                {
                    foreach (XmlNode xtopic in xManifest.SelectNodes("//topic"))
                    {
                        if (xtopic.Attributes["id"].Value.Trim().StartsWith("T:"))
                        {
                            base.WriteMessage(MessageLevel.Info, "--M-- Init... Topic from manifest  " + xtopic.Attributes["id"].Value);

                            if (diagramList[diagramList.Count - 1].AddMapTag(xtopic.Attributes["id"].Value.Trim()))
                            {
                                base.WriteMessage(MessageLevel.Info, "---- --M-- Init... Add map for diagramm");
                            }
                        }
                    }

                }

                if (manifestConceptExist)
                {
                    foreach (XmlNode xtopic in xManifestConcept.SelectNodes("//topic"))
                    {
                        base.WriteMessage(MessageLevel.Info, "--C-- Init... Topic from Manifest Conceptual " + xtopic.Attributes["id"].Value);

                        if (diagramList[diagramList.Count - 1].AddMapTag(xtopic.Attributes["id"].Value.Trim()))
                        {
                            base.WriteMessage(MessageLevel.Info, "---- --C-- Init... Add conceptual map for diagramm");
                        }
                    } 
                }

                base.WriteMessage(MessageLevel.Info, "---- Init... Diagram maps = " + GetDiagramMaps(diagramList[diagramList.Count - 1].DIAG_NAME));
            }
            //--------------------------------------------------------------------------------------------------------------
                                             
            base.WriteMessage(MessageLevel.Info, "init... End");
        }

        /// <summary>
        /// Переопределённый метод для выполнения действий над всеми топиками документации.
        /// Находит все теги diagram в топике и "обогащает" их аттрибутами и внутренними тегами dimap.
        /// </summary>
        /// <param name="document">Доступ с XML документу топика</param>
        /// <param name="key">Полное имя топика</param>
        public override void Apply(XmlDocument document,
          string key)
        {
            XmlNodeList nodeList = null;

            XmlNamespaceManager nsmgr = new XmlNamespaceManager(document.NameTable);

            if (manifestConceptExist)
            {
                XmlDocument manifestConcept = new XmlDocument();
                manifestConcept.Load(manifestConceptFile);
                foreach (XmlNode xtopic in manifestConcept.SelectNodes("//topic"))
                {
                    //base.WriteMessage(MessageLevel.Info, "Apply...concept topic manifest " + xtopic.Attributes["id"].Value.Trim() + " == " + key);
                    if (xtopic.Attributes["id"].Value.Trim() == key)
                    {
                        nsmgr.AddNamespace("ddue", "http://ddue.schemas.microsoft.com/authoring/2003/5");

                        XmlElement root = document.DocumentElement;
                        nodeList = root.SelectNodes("//ddue:diagram", nsmgr);

                        base.WriteMessage(MessageLevel.Info, "Apply... Find " + nodeList.Count + " diagrams in conceptual topic " + key);
                    }
                }
            }
            
            if(nodeList == null)
            {
                nodeList = document.SelectNodes("//diagram");
                base.WriteMessage(MessageLevel.Info, "Apply... Find " + nodeList.Count + " diagrams in topic " + key);
            }
            

            //base.WriteMessage(MessageLevel.Info, "Apply... Find " + nodeList.Count + " diagrams in topic " + document.OuterXml);
            int counter = 0;

            foreach (XmlNode xdiagram in nodeList)
            {
                string diagramName = xdiagram.Attributes["filename"].Value;
                //string diagramFile = diagramPath + diagramName;

                XmlAttribute imgPathAttr = document.CreateAttribute("imgpath");
                XmlAttribute mapNameAttr = document.CreateAttribute("mapname");

                imgPathAttr.Value = "..\\Diagrams\\" + diagramName.Remove(diagramName.LastIndexOf('.')) + ".jpg";
                mapNameAttr.Value = "Click_" + diagramName.Remove(diagramName.LastIndexOf('.'));

                xdiagram.Attributes.Append(imgPathAttr);
                xdiagram.Attributes.Append(mapNameAttr);

                counter++;

                try
                {
                    xdiagram.InnerXml += GetDiagramMaps(diagramName);
                    base.WriteMessage(MessageLevel.Info, "---- ---- Apply... Write tags into = " + xdiagram.OuterXml);
                }
                catch (XmlException e)
                {
                    base.WriteMessage(MessageLevel.Error, "---- ----Apply... Error writing tag in InnerXml ");
                }
                finally
                {
                    base.WriteMessage(MessageLevel.Info, "---- ---- Apply... Topic "+key+" have content :");
                    //base.WriteMessage(MessageLevel.Info, document.OuterXml);
                }
            }
        }

        /// <summary>
        /// Находит диаграмму по имени и возвращает набор тегов dimap
        /// </summary>
        /// <param name="diagramName">Имя диаграммы</param>
        /// <returns>Набор тегов</returns>
        private string GetDiagramMaps(string diagramName)
        {
            foreach (ClickDiagramm cd in diagramList.ToArray())
            {
                if (cd.DIAG_NAME == diagramName)
                    if (cd.DIAG_MAPS != null)
                        return cd.DIAG_MAPS;
            }

            base.WriteMessage(MessageLevel.Warn, "---- ---- Apply... Diagram " + diagramName + " not finded or maps tag is NULL");
            return "";
        }

        /// <summary>
        /// Находит диаграмму по имени и возвращает законченный тег diagramm
        /// </summary>
        /// <param name="diagramName">Имя диаграммы</param>
        /// <returns>Тег diagram</returns>
        //private string GetDiagramTag(string diagramName)
        //{
        //    foreach (ClickDiagramm cd in diagramList.ToArray())
        //    {
        //        if (cd.DIAG_NAME == diagramName)
        //            return cd.GetDiagramTag();
        //    }

        //    base.WriteMessage(MessageLevel.Warn, "---- ---- Apply... Diagram " + diagramName + " not finded or diagram tag is NULL");
        //    return "";
        //}
    }
}
